Skip to content

fix(change-quality): read Git paths without quoting or newline splitting - #8364

Open
gcl-coder wants to merge 2 commits into
loopx-project:mainfrom
gcl-coder:fix/change-quality-scope-paths
Open

gcl-coder wants to merge 2 commits into
loopx-project:mainfrom
gcl-coder:fix/change-quality-scope-paths

Conversation

@gcl-coder

@gcl-coder gcl-coder commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

动机 / Motivation

仓库里只要出现非 ASCII 或特殊文件名,change_quality prepare 就会出错:非 ASCII 名会被 Git 默认的 core.quotepath 输出成八进制转义串,_hash_untracked_file 拿着这个字面串 open() 直接 FileNotFoundError;含换行的名字被切成两条记录;首尾空格被 .strip() 吃掉。

修好 prepare 之后还有第二段:record 提交的文件证据要能被 verify 认出来。旧实现里 result.py 的 _relative_path 会 strip、把反斜杠换成斜杠,证据 ref 解析还会折叠空白,于是同名文件到记录阶段变成另一个名字,报 unknown evidence。

本 PR 同时修这两段,并保留本能力原有的 Git 等待上限。

改动思路 / Approach

  • 路径解析只在既有有界 _git 之上加 -z 分帧:_name_only 按 NUL 切记录,不再 strip、不再替换反斜杠;committed / staged / unstaged / untracked 四处统一加 -z。
  • GIT_PROBE_TIMEOUT_SECONDS、GitProbeUnavailable、独立 session、取消处理与共享进程回收保持原样(上一版 head 曾把整份旧快照覆盖上去,删掉了这些,本版已恢复)。
  • result.py 的 evidence_refs、risk.path、covers_paths 保留确切 repo-relative 路径:不再 strip、不再折叠空白、不把反斜杠当分隔符;绝对路径与 .. 仍拒绝。

具体改动 / Changes

对主干的风险 / Risks

  • 本地 tests/test_change_quality_scope_paths.py 与 tests/test_change_quality_git_budget.py 共 22 passed,包含原有的 10 秒预算与取消测试。
  • tests/capabilities/test_change_quality*.py 需要打包后的 TypeScript effect runtime,本机抛 EffectRuntimeHostPermissionError,因此 prepare→record→verify 的完整 CLI 旅程未能本地执行;远端 CI 会覆盖。
  • 原生 Windows 未执行;-z 是 Git 通用选项。
  • 指纹算法、receipt 协议与权限边界未改。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

REQUEST_CHANGES:2 个 P2。NUL 分隔修复了中文文件名,但同时移除了原有 Git 等待上限;部分新接受的合法文件名仍不能完成路径证据的记录。

精确 head:917ebbde55b0320714d352f8e2ff8447b36e9bf0

动机 / Motivation

用 change-quality 审查含中文或特殊文件名的开发者,需要枚举真实文件并把证据记录为可验证收据。旧版会把 quoted 或多行名字当成错误路径;新版本希望保留名字,让 prepare 后可直接 record 和 verify。普通 Unicode 全旅程已通过,但有界失败和特殊路径的文件证据记录仍失败。本 PR 不新增激活、模型执行或合并权限;exact-scope 路径与失败语义属于当前切片。当前仍缺既有有界 Git 合同及新接受路径的完整 record 旅程。

改动思路 / Approach

变更把四类 Git 路径枚举改成 --name-only -z / ls-files -z,并按 NUL 分帧;Git 的引号转义、行分隔及 strip 都不再改变文件名。指纹算法与 bytes-mode diff 内容仍保留。这个方向正确,中文、日本語和 accent 文件名现已能经过真实 prepare、record 和 verify。

但 NUL 解析与进程生命周期是独立职责。最小方案是在现有有界 Git adapter 上修改路径 framing,而不是删除 timeout、typed error 与 process retirement。路径身份还必须贯穿既有 result owner;新增一个范围中正确的名字、随后在记录阶段再规范成另一个名字,不能完成用户要求。无需增加第二个 scope 或状态 owner。

Python 仍是现有 Git provider IO;共享 runtime 负责进程回收,没有新增 Core 决策 owner。当前切片必须保留既有等待上限,并让新接受路径贯穿已有收据消费者。

具体改动 / Changes

全 PR 为 2 文件,+104/-66;scope.py +23/-66,新增路径测试 81 行。完整 diff 除 framing 外还删除已有预算常量、GitProbeUnavailable、_retire_owned_probe、Popen/communicate 超时及取消处理;这不是单纯字符编码修复,PR 原说明没有披露这个默认行为变化。

关键代码讲解

  1. _git L12 改成没有 timeout 的 subprocess.run;encoding 仍只作用于 text 模式,但有限等待、独立 session 与 shared retirement 全部丢失。
  2. _name_only L53 按 NUL 拆分并保留名字,解决 quoted Unicode 和 newline 分片;四个调用点都传 -z,生产 scope 的 changed_files 可保持实际名字。
  3. build_change_quality_scope L109 汇合 committed/staged/unstaged/untracked 并哈希;下游 result._relative_path L108 和 _normalize_evidence_ref 仍做文本规范化。后者不在 diff 内,却是新接受路径完成收据的必经消费者。

规范依据是不可变 base c63a8f9cfc023ff22f39db5cb8b734da7653e83d 中的 loopx/capabilities/change_quality/README.md,在读 diff 前已核对,PR 未改其验收边界。default-off 与 exact-scope-record-verify:默认关闭、exact-scope record/verify、stale 拒绝保持在普通路径;新接受文件名和 Git 故障恢复还没有完整满足公开收据旅程。 repository-experience 的既有有用切片建议在当前 head 采用:按用户能够完成的同步/收据任务判断,不把测试数、字段或父路线图完成当作验收。

对主干的风险 / Risks

PASS:新增6项路径测试、UTF-8 和既有普通收据测试;所选完整集合为55 passed、6 failed。相同旧测试集合在不可变 base 为55 passed;head 的6项失败来自既有 git_budget(4项缺少预算属性、2项取消夹具因调用接口变化报 TypeError),不能把绿色新测试当作原有运行语义仍有效。

[P2] 保留原有 Git deadline 与回收

真实公开 prepare 使用 native Git fsmonitor 阻塞 helper,保持默认10秒不改。base 约11.17秒返回 typed Git error、helper 停止且 runtime 未变;head 到13秒仍无输出,只能由外层夹具终止整个测试组。head helper 的停止是外层清理造成,不是产品回收证明。请在现有有界 _git 上应用 NUL 修复,恢复 error、取消和 owned-process retirement,并重跑现有测试及真实 helper 恢复。

[P2] 让路径身份贯穿 record

真实 prepare→record→verify:普通 Unicode 文件能生成有效收据;带前后空格、内含换行、POSIX literal backslash 的文件都可 prepare,却在提交与 scope 完全相同的 path 证据时分别报 unknown evidence: path:padded.py、path:new line.py、path:back/slash.py。失败原因是 result 的 strip/whitespace collapse/backslash replacement 改写了名字。这里只声称正常的文件证据路径失败;validator-only 引用可能绕过,不代表所有收据都绝对无法生成。请让 evidence、risk.path、covers_paths 共同保留确切 repo-relative 路径,仍验证绝对路径和 .. 越界,补完整公开 round trip。首次夹具把 --result-json 写成 --result,被 argparse 拒绝;未计入能力失败,已保留并用正确参数补跑。

standard premerge 的6项直接检查通过;catalog/risk 合计7项按原生 gate 通过,另有 maintainability advisory FAIL。后者在相同 base/head 的完整450字节输出相同,Lark 模块、规则和配置未改,原阈值保留;它不解释本次已复现的回归。未查询、轮询或等待远端 CI。原生 Windows 未运行;POSIX 模拟分支不能认证原生 Windows。所有写入仅在隔离仓库/夹具;没有用户 Host 安装、付费模型或生产采用测试。

我的整体评价 / Verdict

long_horizon:regression;一个阻塞 Git helper 再次可以让工作长期不返回,新接受路径仍需人为绕过文件证据。 user_experience:regression;正常流程不增加确认轮次,但失败路径仍不能可靠继续,需要在现有 owner 内修复。架构切片和代码量基本适配,维持 proportionate;方向正确与部分修复通过不能覆盖当前 P2。恢复既有超时 owner 比引入新 runner 小,路径 parser 修复需要连同既有消费者一起交付。

此处没有 rendered presentation 改动;已检查公开 CLI、provider 和持久收据/清理路径,visual_review 为 not_applicable。未验证范围:原生 Windows、生产 Host 采用、长期完整成本。没有新增共享 enum、actor 或权限;Git-specific 诊断留在 Git provider,没有把产品或 benchmark 条件塞入通用义务。安全范围不变:review 不是 merge、安装或执行模型的授权。修复后需对新精确 head 重跑完整 PR 和上述真实边界反例。

English verdict: REQUEST_CHANGES — 917ebbd; the Git deadline was removed and accepted special paths still fail file-specific receipt recording.

raise
return subprocess.CompletedProcess(
args=argv, returncode=process.returncode, stdout=stdout, stderr=stderr
return subprocess.run(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 这里的替换同时移除了已有 GIT_PROBE_TIMEOUT_SECONDS、GitProbeUnavailable、独立 session、timeout/cancellation 及 shared retirement;NUL 路径修复并不需要删除这些合同。真实公开 prepare + native Git fsmonitor、默认10秒:base 约11.17秒返回 typed error 并停止 helper,head 到13秒仍无响应,只能由外层夹具终止。现有预算/取消集合也出现6项失败。请在原有有界 _git 上保留 -z/framing 修复,恢复原错误与进程生命周期,并重跑完整现有测试和真实 helper 恢复。

result = _git(repo_root, *args, text=True)
if result.returncode != 0:
detail = str(result.stderr or "").strip()
raise ValueError(f"git {' '.join(args)} failed: {detail}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 这里现在保留了合法名字,但 downstream record 的 _normalize_evidence_ref/_relative_path 仍 strip/collapse whitespace 并把 backslash 改成 slash。真实 prepare→record:带前后空格、内含换行和 literal POSIX backslash 的文件均 prepare 成功,提交 scope 报告的原路径后却分别被改成 path:padded.py、path:new line.py、path:back/slash.py,报 unknown evidence;普通 Unicode 路径则全旅程成功。请让 evidence、risk.path、covers_paths 保留同一精确 repo-relative 路径,并同时保留绝对/.. 越界拒绝。validator-only 引用的可能绕过不等于文件证据已可用。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

Copy link
Copy Markdown
Contributor Author

两条 P2 都处理了,新 head 需重看。

P2-1 恢复有界 Git。 你说得对:上一版 head 是把一份旧 main 快照的 scope.py 整份覆盖上去,所以把 #8169 合并后的 GIT_PROBE_TIMEOUT_SECONDS、GitProbeUnavailable、独立 session、取消处理与共享进程回收一起删掉了。这一版在同一处既有 _git 上只叠加 -z 分帧,预算、错误类型与进程生命周期全部保留。现有 tests/test_change_quality_git_budget.py 的 8 项(含超时、取消、回收)在本机通过。

P2-2 路径身份贯穿 record。 result.py 里三处改写去掉了:_relative_path 不再 strip、不再把反斜杠换成斜杠;证据 ref 解析改用逐字保留的 _exact_text,不再 " ".join(split()) 折叠空白;covers_paths 直接取原始数组,不再先经过 _bounded_text_list。evidence_refs[].path、risk.path、covers_paths 因此和 scope 报出的名字一致。绝对路径与 .. 仍拒绝,/abs/file.txt、../outside.py、a/../../b 都有用例。

新增用例覆盖:" padded.py "、含换行的 line\nbreak.txt、POSIX 字面反斜杠 back\slash.py、café.txt——这些名字经真实 Git 进入 scope 后,用同样的名字构造 path: 证据能通过 _validate_evidence_targets,不会再报 unknown evidence。

本地 tests/test_change_quality_scope_paths.py + tests/test_change_quality_git_budget.py 共 22 passed。tests/capabilities/test_change_quality*.py 在本机缺打包的 TypeScript effect runtime(EffectRuntimeHostPermissionError),所以完整 prepare→record→verify CLI 旅程没能本地跑完,这点如实保留;远端 CI 会覆盖。Windows 未执行。

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

APPROVE:本 head 未发现阻断项。上轮发现已用当前版本的真实入口重新验证,以下结论覆盖完整 PR。

精确 head:2157052a418d00c3d458bcdcc73aaf468714904b

动机 / Motivation

使用 change-quality 审查中文或特殊文件名的开发者,需要发现真实文件并把文件证据保存为可验证收据。旧 prepare 把 Git 引号或换行当成路径,可能找不到文件;新 head 在枚举和记录两端保留名字,原有等待上限继续有效。Unicode、前后空格、内含换行及 POSIX 字面反斜杠均完成真实 prepare、record、verify;普通与关闭态保持原行为。不改动会继续保留已复现的等待或文件身份问题;验证对象是开发者能否完成原任务、看见失败并重试,而不是仅检查 helper 返回或测试数量。本 PR 不增加远端写入、合并、安装、模型执行或额外调用权限;原生 Windows 与生产长期收益不在本地资格内。

改动思路 / Approach

路径 framing 和进程生命周期是不同职责。当前在原有有界 Git adapter 之上应用 NUL,再由既有 result codec 保留同一 repo-relative 名字;typed qualification 仍由原 owner 决定。只修 prepare 会在 record 阶段断开,因此两端一起修改有实际必要,不需要第二个路径模型。

Git/文件名/目录清理属于现有 Python provider IO;进程回收复用共享 runtime,资格决策仍归原 typed owner。本切片同时闭合路径枚举与现有收据消费者,保留原预算,无需新 schema 或独立路径 owner。最强反对理由是预算可能拒绝合法慢操作、额外清理需要理解 Git 元数据,以及路径 codec 必须同时守住越界边界;这些成本已由现有 owner 和对应真实反例验证约束。没有新增安装、配置、确认或信息重填轮次。

具体改动 / Changes

本 PR 全量为3文件,+186/-25。另单独核对上一评审 head 到当前 head 的修复:917ebbde 的预算删除已恢复,特殊路径记录由既有 result.py 一起修复。历史失败保持其原有结论,没有将其重写为通过,也没有继承上次批准趋势。

关键代码讲解

  1. _git L41 保留现有 bytes/text 模式、10秒等待、GitProbeUnavailable、取消和共享进程回收;这次 whole-PR diff 已不再删除原生命周期。

  2. _name_only L101 只用 NUL 分帧,不 strip 或替换反斜杠。build_change_quality_scope 的 committed、staged、unstaged、untracked 四个来源统一传 -z,指纹内容算法不另造版本。

  3. _relative_path L123 经 _exact_text 保留首尾空格、换行和 POSIX 字面反斜杠,仍拒绝绝对路径与 ..;_normalize_evidence_ref L154 保留冒号后的真实身份,risk.path 与 covers_paths 复用这条路径。

规格依据:loopx/capabilities/change_quality/README.md;spec_revision:c63a8f9cfc023ff22f39db5cb8b734da7653e83d。Configure-A-Goal、Protocol-1、Protocol-5-6、Provider-Boundary 在本 head 均为 implemented,分别映射到上述现有入口、完整 CLI 正反例和持久状态读回。它们指向原 README 的章节/编号步骤,不新增父级 roadmap 门槛。

对主干的风险 / Risks

PASS:scope_paths、原 Git budget 和全部 change_quality 能力测试78 passed;相同旧集合在不可变 base 为64 passed。真实公开 prepare→record→verify 的 Unicode、前后空格、换行、POSIX 字面反斜杠四类文件均生成有效收据,普通 enabled 全旅程、disabled prepare 和 stale verify 的完整规范化输出/退出码与 base 一致。

另用同一仓库同时构造 committed、staged、unstaged、untracked 四种来源:head 逐一保留预期名字,带 path 证据、risk.path 和 covers_paths 的真实 record/verify 成功;绝对路径与 .. 在 record 被拒,改变一个字节后 verify 返回 stale_receipt。原生 Git fsmonitor 持续写心跳并阻塞:保持默认10秒,base 约10.84秒、head 约11.27秒均返回 typed error,helper 心跳停止且 runtime 未变;关闭故障后恢复。

原生 standard premerge 的6项直接检查和10项选择检查通过 gate。首次运行因工作树缺 TypeScript 开发依赖失败,已保留失败记录,安装 npm ci --ignore-scripts 后在相同未改 head 重跑通过。另有原 Lark 模块 metric advisory FAIL:当前 base/head 完整450字节输出一致,相关模块、oracle、配置与阈值未变;没有把它改成 PASS。未查询或等待远端 CI。

我的整体评价 / Verdict

long_horizon:improved;Unicode、前后空格、内含换行及 POSIX 字面反斜杠均完成真实 prepare、record、verify;普通与关闭态保持原行为。 user_experience:improved;原有入口、关闭/预览态与普通重放不增加操作轮次,失败后由原 caller 继续。这里的改善限定于验证过的本地任务和恢复,不宣称已测得生产 token、费用或长期净收益。

代码规模与已复现问题相称,判为 proportionate;枚举与消费者共同保持身份是必要闭环,重用现有 bounded adapter/codec;没有新 schema 或多余版本兼容分支。没有 rendered presentation 改动;已检查公开 CLI、Git provider 及持久收据/候选清理旅程。未验证范围:原生 Windows、生产 Host 采用、长期完整成本与收益。共享 typed vocabulary、权限和通用义务不变。评审结论与旧 blocking review 的正式状态、readiness 及维护者合并决定分别处理。

English verdict: APPROVE — 2157052; exact path receipt round trips pass while bounded Git behavior is preserved.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants